package com.malred.spring;

import com.malred.services.appConfig;

import java.beans.Introspector;
import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author malguy-wang sir
 * @create ---
 */
//容器类
public class myApplicationContext {
    private ConcurrentHashMap<String,beanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
    private ConcurrentHashMap<String,Object> singletonObjects = new ConcurrentHashMap<>();
    private ArrayList<beanPostProcessor> beanPostProcessors = new ArrayList<>();
    //扫描
    public myApplicationContext(Class configClass) throws Exception {
        this.configClass = configClass;
        //判断这个类是否存在指定注释
        if (configClass.isAnnotationPresent(ComponentScan.class)) {
            //获取注释类
            ComponentScan annotation = (ComponentScan) configClass.getAnnotation(ComponentScan.class);
            //获取注释属性
            String path = annotation.value();//com.malred.services
            //改为 /
            path = path.replace(".", "/");
//            System.out.println(path);// com/malred/services
            //获得类加载器（为了获取真实路径）
            ClassLoader classLoader = myApplicationContext.class.getClassLoader();
            //获取资源路径（对应一个文件夹）
            URL resource = classLoader.getResource(path);
            File file = new File(resource.getFile());
            System.out.println(file);//D:\java&idea\springHandOwn\out\production\springHandOwn\com\malred\services
            //如果是文件夹
            if (file.isDirectory()) {
                //获取目录下文件
                File[] files = file.listFiles();
                for (File f : files) {
                    //获取文件的绝对路径
                    String fileName = f.getAbsolutePath();
//                    System.out.println(fileName);
                    //获取全类名
                    String className =
                            path.replace("/", ".") +
                                    fileName.substring(fileName.lastIndexOf("\\"), fileName.indexOf(".class")).replace("\\", ".");
//                    System.out.println(className);
                    //寻找class文件
                    if (fileName.endsWith(".class")) {
                        //传入全类名，获取类
                        Class<?> aClass = null;
                        try {
                            aClass = classLoader.loadClass(className);
                        } catch (ClassNotFoundException e) {
                            e.printStackTrace();
                        }
                        //如果是组件
                        if (aClass.isAnnotationPresent(Component.class)) {
                            //如果是后置处理器(用isAssignableFrom来判断)
                            if(beanPostProcessor.class.isAssignableFrom(aClass)){
                                beanPostProcessor instance = (beanPostProcessor) aClass.newInstance();
                                beanPostProcessors.add(instance);//加入后置处理器容器
                            }
                            //获取bean的名字
                            Component component = aClass.getAnnotation(Component.class);
                            String beanName = component.value();
                            if(beanName.equals("")){
                                //如果没有注解的value为空,生成名字(首字母小写)
                                beanName = Introspector.decapitalize(aClass.getSimpleName());
                            }
                            //beandefinition
                            beanDefinition beanDefinition = new beanDefinition();
                            beanDefinition.setType(aClass);
                            if (aClass.isAnnotationPresent(scope.class)) {
                                scope scopeAnnotation = aClass.getAnnotation(scope.class);
                                beanDefinition.setScope(scopeAnnotation.value());
                            } else {
                                //没有注解默认单例
                                beanDefinition.setScope("singleton");
                            }
                            //放入存放定义信息的集合,后续根据集合信息创建bean
                            beanDefinitionMap.put(beanName,beanDefinition);
                        }
                    }
                }
            }
        }
        for (String beanName : beanDefinitionMap.keySet()) {
            //获取定义信息
            beanDefinition beanDefinition = beanDefinitionMap.get(beanName);
            //判断是不是单例
            if(beanDefinition.getScope().equals("singleton")){
                Object bean = createBean(beanName, beanDefinition);
                singletonObjects.put(beanName,bean);//存入单例池
            }
        }
    }
    private Object createBean(String beanName,beanDefinition beanDefinition){
        Class clazz = beanDefinition.getType();//获取类
        Object instance = null;//通过无参构造方法创建实例
        try {
            instance = clazz.getConstructor().newInstance();
            //遍历字段
            //依赖注入
            for (Field f : clazz.getDeclaredFields()) {
                if(f.isAnnotationPresent(AutoWired.class)){
                    f.setAccessible(true);//打开赋值
                    f.set(instance,getBean(f.getName()));//当前字段名作为bean名字去寻找并创建bean
                }
            }
            //instanceof用于判断对象
            //回调
            if(instance instanceof beanNameAware){
                ((beanNameAware)instance).setBeanName(beanName);
            }
            for (beanPostProcessor beanPostProcessor : beanPostProcessors) {
                instance = beanPostProcessor.postProcessorBeforeInitialization(beanName,instance);
            }
            //初始化
            if(instance instanceof initializingBean){
                ((initializingBean)instance).afterPropertiesSet();
            }
            for (beanPostProcessor beanPostProcessor : beanPostProcessors) {
                instance = beanPostProcessor.postProcessorAfterInitialization(beanName,instance);
            }
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return instance;
    }

    private Class configClass;

    public Object getBean(String beanName) {
        //根据bean名称获取bean信息
        beanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        if(beanDefinition == null) throw new NullPointerException();
        else {
            //判断单例还是多例
            String scope = beanDefinition.getScope();
            if(scope.equals("singleton")){
                //从单例池里创建
                Object bean = singletonObjects.get(beanName);
                if(bean==null){
                    Object o = createBean(beanName, beanDefinition);//如果为空就创建
                    singletonObjects.put(beanName,o);//存入
                }
                return bean;
            }else {
                //多例
                return createBean(beanName, beanDefinition);
            }
        }
    }
}
